﻿using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Ordering.Domain.Aggregate;
using Ordering.Domain.SeedWork;

namespace Ordering.Infrastructure
{
    public class OrderingDbContext : DbContext, IUnitOfWork
    {
        public OrderingDbContext(DbContextOptions<OrderingDbContext> options)
            : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Buyer>()
                .Property(a => a.Id)
                .HasValueGenerator<IdGenerator>();
            modelBuilder.Entity<Order>()
                .Property(a => a.Id)
               .HasValueGenerator<IdGenerator>();
            modelBuilder.Entity<OrderItem>()
                .Property(a => a.Id)
               .HasValueGenerator<IdGenerator>();
        }

        public DbSet<Order> Orders => Set<Order>();

        public DbSet<Buyer> Buyers => Set<Buyer>();

        public async Task SaveEntitiesAsync(CancellationToken token)
        {
            var mediator = Database.GetService<IMediator>();
            mediator?.DispatchDomainEventsAsync(this);
            await SaveChangesAsync(token);
        }

        private IDbContextTransaction? _transaction;

        public bool HasActivedTransaction => _transaction != null;

        public async Task<IDbContextTransaction> BegionTransactionAsync(CancellationToken token)
        {
            if (_transaction == null)
            {
                _transaction = await Database.BeginTransactionAsync(token);
            }
            return _transaction;
        }

        public async Task CommitTransactionAsync(CancellationToken token)
        {
            try
            {
                if (_transaction != null)
                {
                    await _transaction.CommitAsync(token);
                }
            }
            finally
            {
                _transaction = null;
            }
        }

        public async Task RollbackTransactionAsync(CancellationToken token)
        {
            try
            {
                if (_transaction != null)
                {
                    await _transaction.RollbackAsync(token);
                }
            }
            finally
            {
                _transaction = null;
            }
        }
    }
}